use redis::{Client, Connection, RedisResult, Commands, AsyncCommands};
use serde::{Deserialize, Serialize};
use std::time::Duration;
use tracing::{debug, warn};

pub struct RedisCache {
    client: Client,
}

impl RedisCache {
    pub fn new(redis_url: &str) -> RedisResult<Self> {
        let client = Client::open(redis_url)?;
        Ok(Self { client })
    }
    
    pub async fn get_connection(&self) -> RedisResult<Connection> {
        self.client.get_connection()
    }
    
    // 基本的键值操作
    pub async fn set<K, V>(&self, key: K, value: V, ttl: Option<Duration>) -> RedisResult<()>
    where
        K: redis::ToRedisArgs,
        V: redis::ToRedisArgs,
    {
        let mut conn = self.get_connection().await?;
        
        if let Some(ttl) = ttl {
            conn.set_ex(key, value, ttl.as_secs() as usize)?;
        } else {
            conn.set(key, value)?;
        }
        
        Ok(())
    }
    
    pub async fn get<K, V>(&self, key: K) -> RedisResult<Option<V>>
    where
        K: redis::ToRedisArgs,
        V: redis::FromRedisValue,
    {
        let mut conn = self.get_connection().await?;
        let result: RedisResult<V> = conn.get(key);
        
        match result {
            Ok(value) => Ok(Some(value)),
            Err(redis::RedisError::from(std::io::Error::new(
                std::io::ErrorKind::NotFound,
                "Key not found",
            ))) => Ok(None),
            Err(e) => Err(e),
        }
    }
    
    pub async fn del<K>(&self, key: K) -> RedisResult<()>
    where
        K: redis::ToRedisArgs,
    {
        let mut conn = self.get_connection().await?;
        conn.del(key)?;
        Ok(())
    }
    
    pub async fn exists<K>(&self, key: K) -> RedisResult<bool>
    where
        K: redis::ToRedisArgs,
    {
        let mut conn = self.get_connection().await?;
        let result: i32 = conn.exists(key)?;
        Ok(result > 0)
    }
    
    // 哈希表操作
    pub async fn hset<K, F, V>(&self, key: K, field: F, value: V) -> RedisResult<()>
    where
        K: redis::ToRedisArgs,
        F: redis::ToRedisArgs,
        V: redis::ToRedisArgs,
    {
        let mut conn = self.get_connection().await?;
        conn.hset(key, field, value)?;
        Ok(())
    }
    
    pub async fn hget<K, F, V>(&self, key: K, field: F) -> RedisResult<Option<V>>
    where
        K: redis::ToRedisArgs,
        F: redis::ToRedisArgs,
        V: redis::FromRedisValue,
    {
        let mut conn = self.get_connection().await?;
        let result: RedisResult<V> = conn.hget(key, field);
        
        match result {
            Ok(value) => Ok(Some(value)),
            Err(redis::RedisError::from(std::io::Error::new(
                std::io::ErrorKind::NotFound,
                "Field not found",
            ))) => Ok(None),
            Err(e) => Err(e),
        }
    }
    
    pub async fn hdel<K, F>(&self, key: K, field: F) -> RedisResult<()>
    where
        K: redis::ToRedisArgs,
        F: redis::ToRedisArgs,
    {
        let mut conn = self.get_connection().await?;
        conn.hdel(key, field)?;
        Ok(())
    }
    
    pub async fn hgetall<K, V>(&self, key: K) -> RedisResult<Vec<V>>
    where
        K: redis::ToRedisArgs,
        V: redis::FromRedisValue,
    {
        let mut conn = self.get_connection().await?;
        let result: Vec<V> = conn.hgetall(key)?;
        Ok(result)
    }
    
    // 列表操作
    pub async fn lpush<K, V>(&self, key: K, value: V) -> RedisResult<()>
    where
        K: redis::ToRedisArgs,
        V: redis::ToRedisArgs,
    {
        let mut conn = self.get_connection().await?;
        conn.lpush(key, value)?;
        Ok(())
    }
    
    pub async fn rpush<K, V>(&self, key: K, value: V) -> RedisResult<()>
    where
        K: redis::ToRedisArgs,
        V: redis::ToRedisArgs,
    {
        let mut conn = self.get_connection().await?;
        conn.rpush(key, value)?;
        Ok(())
    }
    
    pub async fn lpop<K, V>(&self, key: K) -> RedisResult<Option<V>>
    where
        K: redis::ToRedisArgs,
        V: redis::FromRedisValue,
    {
        let mut conn = self.get_connection().await?;
        let result: RedisResult<V> = conn.lpop(key, None);
        
        match result {
            Ok(value) => Ok(Some(value)),
            Err(redis::RedisError::from(std::io::Error::new(
                std::io::ErrorKind::NotFound,
                "List empty",
            ))) => Ok(None),
            Err(e) => Err(e),
        }
    }
    
    pub async fn rpop<K, V>(&self, key: K) -> RedisResult<Option<V>>
    where
        K: redis::ToRedisArgs,
        V: redis::FromRedisValue,
    {
        let mut conn = self.get_connection().await?;
        let result: RedisResult<V> = conn.rpop(key, None);
        
        match result {
            Ok(value) => Ok(Some(value)),
            Err(redis::RedisError::from(std::io::Error::new(
                std::io::ErrorKind::NotFound,
                "List empty",
            ))) => Ok(None),
            Err(e) => Err(e),
        }
    }
    
    // 集合操作
    pub async fn sadd<K, V>(&self, key: K, value: V) -> RedisResult<()>
    where
        K: redis::ToRedisArgs,
        V: redis::ToRedisArgs,
    {
        let mut conn = self.get_connection().await?;
        conn.sadd(key, value)?;
        Ok(())
    }
    
    pub async fn srem<K, V>(&self, key: K, value: V) -> RedisResult<()>
    where
        K: redis::ToRedisArgs,
        V: redis::ToRedisArgs,
    {
        let mut conn = self.get_connection().await?;
        conn.srem(key, value)?;
        Ok(())
    }
    
    pub async fn smembers<K, V>(&self, key: K) -> RedisResult<Vec<V>>
    where
        K: redis::ToRedisArgs,
        V: redis::FromRedisValue,
    {
        let mut conn = self.get_connection().await?;
        let result: Vec<V> = conn.smembers(key)?;
        Ok(result)
    }
    
    // 过期时间操作
    pub async fn expire<K>(&self, key: K, ttl: Duration) -> RedisResult<()>
    where
        K: redis::ToRedisArgs,
    {
        let mut conn = self.get_connection().await?;
        conn.expire(key, ttl.as_secs() as usize)?;
        Ok(())
    }
    
    pub async fn ttl<K>(&self, key: K) -> RedisResult<Option<Duration>>
    where
        K: redis::ToRedisArgs,
    {
        let mut conn = self.get_connection().await?;
        let result: i32 = conn.ttl(key)?;
        
        if result == -1 {
            Ok(None) // 没有设置过期时间
        } else if result == -2 {
            Ok(None) // 键不存在
        } else {
            Ok(Some(Duration::from_secs(result as u64)))
        }
    }
    
    // 序列化/反序列化辅助方法
    pub async fn set_json<K, V>(&self, key: K, value: &V, ttl: Option<Duration>) -> RedisResult<()>
    where
        K: redis::ToRedisArgs,
        V: Serialize,
    {
        let json = serde_json::to_string(value)
            .map_err(|e| redis::RedisError::from(std::io::Error::new(std::io::ErrorKind::InvalidData, e)))?;
        
        self.set(key, json, ttl).await
    }
    
    pub async fn get_json<K, V>(&self, key: K) -> RedisResult<Option<V>>
    where
        K: redis::ToRedisArgs,
        V: for<'de> Deserialize<'de>,
    {
        if let Some(json_str) = self.get::<K, String>(key).await? {
            let value = serde_json::from_str(&json_str)
                .map_err(|e| redis::RedisError::from(std::io::Error::new(std::io::ErrorKind::InvalidData, e)))?;
            Ok(Some(value))
        } else {
            Ok(None)
        }
    }
    
    // 健康检查
    pub async fn ping(&self) -> RedisResult<()> {
        let mut conn = self.get_connection().await?;
        let result: String = conn.ping()?;
        
        if result == "PONG" {
            debug!("Redis connection healthy");
            Ok(())
        } else {
            Err(redis::RedisError::from(std::io::Error::new(
                std::io::ErrorKind::InvalidData,
                "Unexpected PING response",
            )))
        }
    }
    
    // 清理过期键
    pub async fn cleanup_expired(&self) -> RedisResult<()> {
        // 这里可以实现定期清理过期键的逻辑
        // 实际项目中可能需要使用Redis的EXPIRE策略或定期扫描
        debug!("Redis cleanup completed");
        Ok(())
    }
} 